#pragma once 

#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"
#include "Task.hpp"
#include <iostream>
#include <vector>
#include <queue>

const int g_thread_num = 5;

template<class T>
class ThreadPool
{
private:
    bool IsEmpty()
    {
        return _task_queue.size() == 0;
    }

    void WaitCond()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }

    pthread_mutex_t* GetMutex()
    {
        return &_mtx;
    }

    T GetTask()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

private:
    ThreadPool(int num = g_thread_num)
    :_num(num)
    {
        for (int i = 0; i < num; i++)
        {
            _threads.push_back(new Thread(i, Routine, this));
        }

        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool<T>& other) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;
public:
// 考虑一下多线程使用单例的过程
    static ThreadPool<T> *GetThreadPool(int num = g_thread_num)
    {
        // 可以有效减少未来必定要进行加锁检测的问题
        // 拦截大量的在已经创建好单例的时候，剩余线程请求单例的而直接访问锁的行为
        if (nullptr == thread_ptr) 
        {
            lockGuard lockguard(&mutex);
            // 但是，未来任何一个线程想获取单例，都必须调用getThreadPool接口
            // 但是，一定会存在大量的申请和释放锁的行为，这个是无用且浪费资源的
            // pthread_mutex_lock(&mutex);
            if (nullptr == thread_ptr)
            {
                thread_ptr = new ThreadPool<T>(num);
            }
            // pthread_mutex_unlock(&mutex);
        }
        return thread_ptr;
    }
    // 消费
    // 为了解决this指针参数不匹配的问题，使用static静态成员函数
    // 但是我们需要访问类内的成员，这里我们传入this指针
    static void* Routine(void* args)
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args;
        while (true)
        {
            T task;
            {
                lockGuard lockguard(tp->GetMutex());
                while (tp->IsEmpty())
                    tp->WaitCond();
                // 读取任务
                task = tp->GetTask(); // 任务队列是共享的-> 将任务从共享，拿到自己的私有空间
            }
            task(td->_name);
            // lock
            // while(task_queue_.empty()) wait();
            // 获取任务
            // unlock

            // 处理任务
        }
    }

    // 添加任务
    void pushTask(T& in)
    {
        lockGuard lockguard(&_mtx);
        _task_queue.push(in);
        
        logMessage(DEBUG, "%s", "添加任务成功");

        pthread_cond_signal(&_cond);
    }

    void run()
    {
        for (auto& iter : _threads)
        {
            iter->start();
        }
    }

    void joins()
    {
        for (auto& iter : _threads)
        {   
            iter->join();
        }
    }

    ~ThreadPool()
    {
        for (auto& iter : _threads)
        {   
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread *> _threads;
    std::queue<T> _task_queue;
    int _num;
    pthread_mutex_t _mtx;
    pthread_cond_t _cond;

    static ThreadPool<T> *thread_ptr;
    static pthread_mutex_t mutex;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::thread_ptr = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;